// Kony


#include "AbilitySystem/Abilitys/BaseDamageGameplayAbility.h"

#include "AbilitySystemBlueprintLibrary.h"
#include "AbilitySystemComponent.h"
#include "Interaction/CombatInterface.h"
//使用游戏标签Tag，伤害触发函数
void UBaseDamageGameplayAbility::CauseDamage(AActor* TargetActor)
{
	// 创建一个伤害效果的 SpecHandle，指定效果类（DamageEffectClass）和当前技能等级为 1.f
	FGameplayEffectSpecHandle DamageSpecHandle = MakeOutgoingGameplayEffectSpec(DamageEffectClass, 1.f);
	//遍历你在 DamageTypes 中定义的所有伤害类型及其值，比如火焰伤害、冰霜伤害等
	// for (TTuple<FGameplayTag, FScalableFloat> Pair : DamageTypes)
	// {
	// 	//根据当前技能等级，获取这个伤害类型的具体伤害值。
	// 	const float ScaledDamage = Pair.Value.GetValueAtLevel(GetAbilityLevel());
	// 	//使用 GameplayTag 作为 Key，把对应伤害值以 Caller Magnitude 的方式写入这个 EffectSpec 中。
	// 	UAbilitySystemBlueprintLibrary::AssignTagSetByCallerMagnitude(DamageSpecHandle, Pair.Key, ScaledDamage);
	// }
	//这个是单一伤害类型的写法
	const float ScaledDamage = Damage.GetValueAtLevel(GetAbilityLevel());
	UAbilitySystemBlueprintLibrary::AssignTagSetByCallerMagnitude(DamageSpecHandle, DamageType, ScaledDamage);
	//对目标施加游戏效果，也就是造成伤害等
	GetAbilitySystemComponentFromActorInfo()->ApplyGameplayEffectSpecToTarget(*DamageSpecHandle.Data.Get(), UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(TargetActor));
}
//根据类的默认设置创建伤害效果参数结构体
FDamageEffectParams UBaseDamageGameplayAbility::MakeDamageEffectParamsFromClassDefaults(AActor* TargetActor,
	FVector InRadialDamageOrigin, bool bOverrideKnockbackDirection, FVector InKnockbackDirectionOverride,
	bool bOverrideDeathImpulse, FVector InDeathImpulseDirectionOverride, bool bOverridePitch, float PitchOverride) const
{
	FDamageEffectParams Params;
	//获取世界上下文对象
	Params.WorldContextObject = GetAvatarActorFromActorInfo();
	//伤害游戏效果类
	Params.DamageGameplayEffectClass = DamageEffectClass;
	//源能力系统组件
	Params.SourceAbilitySystemComponent = GetAbilitySystemComponentFromActorInfo();
	//目标能力系统组件，如果目标角色为null 返回null
	Params.TargetAbilitySystemComponent = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(TargetActor);
	//基础伤害 这个是这个技能的基础伤害
	Params.BaseDamage = Damage.GetValueAtLevel(GetAbilityLevel());
	//能力等级
	Params.AbilityLevel = GetAbilityLevel();
	//伤害类型
	Params.DamageType = DamageType;
	//异常触发几率
	Params.DebuffChance = DebuffChance;
	//是否启用异常伤害 如果启用就按照伤害的百分比计算
	Params.DebuffDamagePercentage = DebuffDamagePercentage;
	//异常伤害
	Params.DebuffDamage = DebuffDamage;
	//异常每跳频率
	Params.DebuffDuration = DebuffDuration;
	//异常持续时间
	Params.DebuffFrequency = DebuffFrequency;
	//击杀敌人死亡时冲击量大小
	Params.DeathImpulseMagnitude = DeathImpulseMagnitude;
	//击退力度
	Params.KnockbackForceMagnitude = KnockbackForceMagnitude;
	//击退几率
	Params.KnockbackChance = KnockbackChance;
	//硬直值
	Params.Stagger = Stagger;
	
	const bool bKnockback = FMath::RandRange(1,100) < Params.KnockbackChance;
	if (bKnockback)
	{
		
		//这个是用于默认计算 死亡击飞和技能击退效果的部分，可以给每一个蓝图技能都默认计算，如果c++技能类中额外增加了计算 会覆盖这些。
		if (IsValid(TargetActor))
		{
			// 			FVector InRadialDamageOrigin, bool bOverrideKnockbackDirection, FVector InKnockbackDirectionOveride,
			// bool bOverrideDeathImpulse, FVector InDeathImpulseDirectionOveride, bool bOveridePitch, float OverideOveride) const
			//获取角色到目标的向量，这个是平面的 只用于击退
			// const FVector ToTarget = (TargetActor->GetActorLocation() - GetAvatarActorFromActorInfo()->GetActorLocation()).GetSafeNormal();
			//这个是可以获取带高度的向量，用于实现击飞
			FRotator Rotation = (TargetActor->GetActorLocation() - GetAvatarActorFromActorInfo()->GetActorLocation()).Rotation();
			Rotation.Pitch = 35.f;//设置角度
			//判断蓝图是否要覆盖俯仰角
			if (bOverridePitch)
			{
				Rotation.Pitch = PitchOverride;
			}
			const FVector ToTarget = Rotation.Vector();
			//覆盖击退力俯仰角
			Params.KnockbackForce = ToTarget * Params.KnockbackForceMagnitude; //设置击退力
			Params.DeathImpulse = ToTarget * Params.DeathImpulseMagnitude; //设置死亡冲击方向和力
		}
		//是否从传入的冲击方向覆盖击退向量
		if (bOverrideKnockbackDirection)
		{
			//将击退方向向量标准化（归一化），确保其长度为1，便于后续计算击退力的方向
			InKnockbackDirectionOverride.Normalize();
			//覆盖击退力
			Params.KnockbackForce = InKnockbackDirectionOverride * KnockbackForceMagnitude;
			//是否覆盖俯仰角
			if (bOverridePitch)
			{
				FRotator KnockbackRotation = InKnockbackDirectionOverride.Rotation();
				KnockbackRotation.Pitch = PitchOverride;
				//覆盖击退力俯仰角
				Params.KnockbackForce = KnockbackRotation.Vector() * KnockbackForceMagnitude;
			}
		}
		//是否从传入的敌人死亡冲击方向覆盖击退向量
		if (bOverrideDeathImpulse)
		{
			//将击退方向向量标准化（归一化），确保其长度为1，便于后续计算击退力的方向
			InDeathImpulseDirectionOverride.Normalize();
			//覆盖敌人死亡击退力
			Params.DeathImpulse = InDeathImpulseDirectionOverride * DeathImpulseMagnitude;
			//是否敌人死亡覆盖俯仰角
			if (bOverridePitch)
			{
				FRotator DeathImpulseRotation = InDeathImpulseDirectionOverride.Rotation();
				DeathImpulseRotation.Pitch = PitchOverride;
				//覆盖击退力俯仰角
				Params.DeathImpulse = DeathImpulseRotation.Vector() * DeathImpulseMagnitude;
			}
		}
	}
	//判断是否开启了径向衰减伤害
	if (bIsRadialDamage)
	{
		//是否径向衰减伤害(也就是距离中心越远伤害越低)
		Params.bIsRadialDamage = bIsRadialDamage;
		//径向内半径
		Params.RadialDamageInnerRadius = RadialDamageInnerRadius;
		//径向外半径
		Params.RadialDamageOuterRadius = RadialDamageOuterRadius;
		//径向起源点
		Params.RadialDamageOrigin = InRadialDamageOrigin;
	}
	return Params;
}
//获取对应级别伤害
float UBaseDamageGameplayAbility::GetDamageAtLevel() const
{
	return Damage.GetValueAtLevel(GetAbilityLevel());
}

//从传入的蒙太奇数组中 随机获取一个蒙太奇（主要用于随机攻击动画）,或者 按顺序指定返回
FTaggedMontage UBaseDamageGameplayAbility::GetRandomTaggedMontageFromArray(const TArray<FTaggedMontage>& TaggedMontages,
	 bool bUseSequential)
{
	const int32 NumMontages = TaggedMontages.Num();
	if (TaggedMontages.Num() > 0)
	{
		// 只有一段动画，直接返回
		if (NumMontages == 1)
		{
			return TaggedMontages[0];
		}
		// 随机播放
		if (!bUseSequential)
		{
			const int32 Selection = FMath::RandRange(0, TaggedMontages.Num() - 1);
			return TaggedMontages[Selection];
		}
		// 顺序播放
		const int32 Index = MontageIndex % NumMontages;
		MontageIndex++;
		return TaggedMontages[Index];
	}
	return FTaggedMontage();
}
//通过伤害类型，获取伤害值（这个暂时无用了 以后如果也无用的话可以考虑删掉）
float UBaseDamageGameplayAbility::GetDamageByDamageType(float InLevel, const FGameplayTag& Type)
{
	//检查是否包含类型
	// checkf(DamageTypes.Contains(Type), TEXT("GameplayAbility [%s] 没有这个伤害类型 [%s]"), *GetNameSafe(this), *Type.ToString());
	//通过伤害类型获取伤害值
	// return DamageTypes[Type].GetValueAtLevel(InLevel);
	return 0.f;
}

//当前技能描述
FString UBaseDamageGameplayAbility::GetDescription(int32 Level, const FText& Title, const FText& Description)
{
	const float ScaledDamage = Damage.GetValueAtLevel(Level);
	
	TArray<FStringFormatArg> Args;
	Args.Add(FStringFormatArg(FString::Printf(TEXT("%.1f"), ScaledDamage)));
	Args.Add(FStringFormatArg(FString::Printf(TEXT("%.1f"), FMath::Abs(GetManaCost(Level)))));
	Args.Add(FStringFormatArg(FString::Printf(TEXT("%.1f"), GetCooldown(Level))));
	Args.Add(FStringFormatArg(Level));
	
	return FormatAbilityDescription(Level, Title, Description, Args);
}
//下一级技能描述
FString UBaseDamageGameplayAbility::GetNextLevelDescription(int32 Level, const FText& Title, const FText& Description)
{
	const float ScaledDamage = Damage.GetValueAtLevel(Level);
	
	TArray<FStringFormatArg> Args;
	Args.Add(FStringFormatArg(FString::Printf(TEXT("%.1f"), ScaledDamage)));
	Args.Add(FStringFormatArg(FString::Printf(TEXT("%.1f"), FMath::Abs(GetManaCost(Level)))));
	Args.Add(FStringFormatArg(FString::Printf(TEXT("%.1f"), GetCooldown(Level))));
	Args.Add(FStringFormatArg(Level));
	
	return FormatNextLevelDescription(Level, Title, Description, Args);
}